package com.ruoyi.system.service.impl;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.fasterxml.jackson.databind.cfg.BaseSettings;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.dto.WechatPayParam;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.OrderStatus;
import com.ruoyi.common.enums.UserCourseTimeStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.AliyunSmsUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.UniqueCodeUtils;
import com.ruoyi.common.utils.wechat.WechatPayV3;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.mapper.SpokenOrderMapper;
import com.ruoyi.system.service.*;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.sql.Array;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class SpokenOrderServiceImpl implements ISpokenOrderService {

    @Autowired
    SpokenOrderMapper orderMapper;

    @Autowired
    ISpokenTeacherService teacherService;

    @Autowired
    ISpokenUserCourseTimeService userCourseTimeService;

    @Autowired
    ISpokenCourseTagService courseTagService;

    @Autowired
    WechatPayV3 wechatPayV3;

    @Autowired
    ISpokenUserService userService;

    @Autowired
    ISpokenTeacherTagService teacherTagService;

    @Autowired
    RedisCache redisCache;

    @Autowired
    AliyunSmsUtils aliyunSmsUtils;

    @Autowired
    ISpokenBaseSetService baseSetService;

    @Override
    public List<SpokenOrder> selectList(SpokenOrder order) {
        List<SpokenOrder> spokenOrders = orderMapper.selectList(order);
        for (SpokenOrder spokenOrder : spokenOrders) {
            // 设置状态
            spokenOrder.setStatusText(OrderStatus.getInfoByCode(spokenOrder.getStatus()));
            List<String> tags = new ArrayList<>();
            // 查询教师标签
            SpokenTeacher spokenTeacher = teacherService.selectById(spokenOrder.getTeacherId());
            List<Long> teacherTagIds = Arrays.stream(spokenTeacher.getTagIds().split(",")).map(Long::parseLong).collect(Collectors.toList());
            for (Long tagId : teacherTagIds) {
                SpokenTeacherTag spokenTeacherTag = teacherTagService.selectById(tagId);
                tags.add(spokenTeacherTag.getTagName());
            }
            spokenOrder.setTeacherTags(tags);
            // 已选课节数
            spokenOrder.setChoosedLessonNum(userCourseTimeService.mobileSelectCountByOrderId(spokenOrder.getOrderId()));
            // 过期时间
            if(spokenOrder.getStatus().equals(OrderStatus.PRE_PAY.getCode())){
                // 获取过期时间
                long expire = redisCache.getExpire("order-" + spokenOrder.getOrderNo());
                spokenOrder.setExpireTime(expire);
            }
        }

        return spokenOrders;
    }

    @Transactional
    @Override
    public int insert(SpokenOrder order) {
        int rows = 0;
        Long userId = SecurityUtils.getUserId();
        SpokenOrder orderInfo = null;
        List<SpokenUserCourseTime> spokenUserCourseTimes = order.getUserCourseTimeList();
        // 校验选中的课时中是否有被其他人选择过的
        if(spokenUserCourseTimes != null && spokenUserCourseTimes.size() > 0){
            for (SpokenUserCourseTime spokenUserCourseTime : spokenUserCourseTimes) {
                SpokenUserCourseTime userCourseTime = new SpokenUserCourseTime();
                userCourseTime.setTimeId(spokenUserCourseTime.getTimeId());
                userCourseTime.setChooseDate(spokenUserCourseTime.getChooseDate());
                userCourseTime.setTeacherId(spokenUserCourseTime.getTeacherId());
                List<SpokenUserCourseTime> choosedUserCourseTime = userCourseTimeService.select(userCourseTime);
                // 已被其他人选择
                if(choosedUserCourseTime.size() > 0
                        // 不是自己选择的
                        && !choosedUserCourseTime.get(0).getUserId().equals(userId)
                        // 不是已取消的
                        && !choosedUserCourseTime.get(0).getStatus().equals(UserCourseTimeStatus.CANCEL.getCode())
                        // 不是已请假的
                        && !choosedUserCourseTime.get(0).getStatus().equals(UserCourseTimeStatus.LEAVE.getCode())){
                    throw new ServiceException(choosedUserCourseTime.get(0).getChooseDate() + " " + choosedUserCourseTime.get(0).getCourseTime().getStartTime() + "~" + choosedUserCourseTime.get(0).getCourseTime().getEndTime() + "的课时已被他人选择");
                }
            }
        }

        // 新创建
        if(order.getOrderId() == null){
            // 生成订单号
            String orderNo = UniqueCodeUtils.getUniqueCode("DD");
            order.setOrderNo(orderNo);
            order.setUserId(userId);
            // 获取课节数
            BigDecimal lessonNum = BigDecimal.valueOf(order.getLessonNum());
            // 查询教师每节课价格
            SpokenTeacher spokenTeacher = teacherService.selectById(order.getTeacherId());
            BigDecimal price  = spokenTeacher.getLessonPrice();
            // 设置总价格
            order.setPayPrice(price.multiply(lessonNum));
            // 创建订单
            rows = orderMapper.insert(order);
            // 缓存待支付时间
            redisCache.setCacheObject("order-" + order.getOrderNo().toString(), order.getCreateTime(), 5, TimeUnit.MINUTES);
        }else{
            orderInfo = orderMapper.selectById(order.getOrderId());
            // 二次选课
            rows = 1;
        }

        // 选择了课时， 保存学生选择的课时
        if(order.getUserCourseTimeList() != null && order.getUserCourseTimeList().size() > 0){
            // 筛选出未创建过的课时
            List<SpokenUserCourseTime> newSpokenUserCourseTimes = spokenUserCourseTimes.stream().filter(item -> item.getOrderId() == null).collect(Collectors.toList());
            // 没有此次新添加的
            if(newSpokenUserCourseTimes.size() < 1){
                return rows;
            }

            for (SpokenUserCourseTime spokenUserCourseTime : newSpokenUserCourseTimes) {
                spokenUserCourseTime.setOrderId(order.getOrderId());
                spokenUserCourseTime.setUserId(userId);
                // 已支付后选择的课时变为正常
                if(orderInfo != null && orderInfo.getStatus().equals(OrderStatus.IS_PAY.getCode())){
                    spokenUserCourseTime.setStatus(UserCourseTimeStatus.NORMAL.getCode());
                }

            }
            rows = userCourseTimeService.insert(newSpokenUserCourseTimes);
        }else{
            // 暂未选择课时
            rows = 1;
        }
        return rows;
    }

    @Override
    public Map<String, Object> selectById(Long orderId) {
        Map resulut = new HashMap();
        // 订单信息
        SpokenOrder spokenOrder = orderMapper.selectById(orderId);
        // 过期时间
        if(spokenOrder.getStatus().equals(OrderStatus.PRE_PAY.getCode())){
            // 获取过期时间
            long expire = redisCache.getExpire("order-" + spokenOrder.getOrderNo());
            spokenOrder.setExpireTime(expire);
        }
        // 设置状态
        spokenOrder.setStatusText(OrderStatus.getInfoByCode(spokenOrder.getStatus()));
        // 已选课节数
        spokenOrder.setChoosedLessonNum(userCourseTimeService.selectCountByOrderId(spokenOrder.getOrderId()));
        // 教师信息
        SpokenTeacher spokenTeacher = teacherService.selectById(spokenOrder.getTeacherId());
        // 学生信息
        SpokenUser spokenUser = userService.selectById(spokenOrder.getUserId());
        // 课程分类信息
        SpokenCourseTag spokenCourseTag = courseTagService.selectById(spokenOrder.getCourseTagId());
        // 选择的时间段信息
        List<SpokenUserCourseTime> spokenUserCourseTimes = userCourseTimeService.selectUserCourseTimeByOrderId(orderId);
        // 移动端查询
        if(!SecurityUtils.getLoginUser().getUser().getUserType().equals("00")){
            // 查询课时状态为：待支付、正常、取消、已消课
            List statusList = new ArrayList();
            statusList.add(UserCourseTimeStatus.PRE_PAY.getCode());
            statusList.add(UserCourseTimeStatus.NORMAL.getCode());
            statusList.add(UserCourseTimeStatus.CANCEL.getCode());
            statusList.add(UserCourseTimeStatus.CANCEL_LESSON.getCode());
            spokenUserCourseTimes  = spokenUserCourseTimes.stream().filter(item -> statusList.contains(item.getStatus())).collect(Collectors.toList());
        }

        resulut.put("order", spokenOrder);
        resulut.put("teacher", spokenTeacher);
        resulut.put("student", spokenUser);
        resulut.put("courseTag", spokenCourseTag);
        resulut.put("courseTime", spokenUserCourseTimes);
        return resulut;
    }

    /**
     * 生成支付参数
     * @param orderId
     * @return
     */
    @Override
    public PrepayWithRequestPaymentResponse genPayParam(Long orderId) {

        SpokenOrder spokenOrder = orderMapper.selectById(orderId);
        // 判断支付是否过期
        String redisKey = "order-" + spokenOrder.getOrderNo();
        if(!redisCache.hasKey(redisKey)){
            throw new ServiceException("支付已过期，请重新下单");
        }
        SpokenUser spokenUser = userService.selectById(spokenOrder.getUserId());
        // 支付
        PrepayWithRequestPaymentResponse result = wechatPayV3.weChatJsApiPay(
                WechatPayParam.builder()
                        .outTradeNo(spokenOrder.getOrderNo())
//                        .payPrice(new BigDecimal(0.01))
                        .payPrice(spokenOrder.getPayPrice())
                        .openid(spokenUser.getOpenId())
                        .description("购买课时").build());
        return result;
    }

    @Transactional
    @Override
    public AjaxResult payCallback(HttpServletRequest request) {
        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.put("code", "SUCCESS");
        ajaxResult.put("message", null);
        //解析回调数据
        Transaction transaction = wechatPayV3.weChatJsapiPayCallback(request);

        Assert.isTrue("SUCCESS".equals(transaction.getTradeState().name()), "支付失败");

        // 获取传过去的支付记录编号
        String orderNo = transaction.getOutTradeNo();
        // 更新订单支付状态
        SpokenOrder spokenOrder = selectByNo(orderNo);
        spokenOrder.setStatus(OrderStatus.IS_PAY.getCode());
        spokenOrder.setTradeNo(transaction.getTransactionId());
        spokenOrder.setPayTime(new Date());
        update(spokenOrder);

        // 更新已选择的课时的状态
        SpokenUserCourseTime userCourseTime = new SpokenUserCourseTime();
        userCourseTime.setOrderId(spokenOrder.getOrderId());
        List<SpokenUserCourseTime> SpokenUserCourseTimes = userCourseTimeService.select(userCourseTime);
        for (SpokenUserCourseTime spokenUserCourseTime : SpokenUserCourseTimes) {
            spokenUserCourseTime.setStatus(UserCourseTimeStatus.NORMAL.getCode());
            userCourseTimeService.update(spokenUserCourseTime);
        }

        // 删除redis缓存
        String redisKey = "order-" + spokenOrder.getOrderNo();
        if(redisCache.hasKey(redisKey)){
            redisCache.deleteObject(redisKey);
        }

        // 通知管理员
        String adminPhone = baseSetService.getInfo(4).getBsContent();
        if(!StringUtils.isEmpty(adminPhone)){
            String orderCode = spokenOrder.getOrderNo();  // 订单号
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String createTime = sdf.format(spokenOrder.getCreateTime());    // 下单时间
            String courseTagName = courseTagService.selectById(spokenOrder.getCourseTagId()).getCourseTagName();    // 课程类型
            String teacherName = teacherService.selectById(spokenOrder.getTeacherId()).getSysUser().getNickName();  // 教师名称
            Integer lessonNum = spokenOrder.getLessonNum();  // 课程包
            SpokenUser spokenUser = userService.selectById(spokenOrder.getUserId());
            String studentName = spokenUser.getSysUser().getNickName();    // 学生昵称
            String studentPhone = !StringUtils.isEmpty(spokenUser.getSysUser().getPhonenumber()) ? spokenUser.getSysUser().getPhonenumber() : "暂无";   //学生手机号
            String englishName = !StringUtils.isEmpty(spokenUser.getEnglishName()) ? spokenUser.getEnglishName() : "暂无";
            String templateCode = aliyunSmsUtils.getPayTemplateCode();
            String smsParam = "{\"orderid\": \"" + orderCode + "\", " +
                                "\"time\": \"" + createTime + "\", " +
                                "\"type\": \"" + courseTagName + "\", " +
                                "\"name\": \"" + teacherName + "\", " +
                                "\"package\": \"" + lessonNum + "节\", " +
                                "\"phone\": \"" + studentPhone + "\", " +
                                "\"englisname\": \"" + englishName + "\"}";
            SendSmsResponse sendSmsResponse = aliyunSmsUtils.sendMessage(aliyunSmsUtils.getSignName(), templateCode, adminPhone, smsParam);
            // 发送成功
            if(sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
                System.out.println("管理员的下单通知成功");
                System.out.println(smsParam);
            }

        }

        return ajaxResult;
    }


    @Override
    public SpokenOrder selectByNo(String orderNo) {
        return orderMapper.selectByNo(orderNo);
    }

    @Override
    public int update(SpokenOrder order) {
        return orderMapper.update(order);
    }

    /**
     * 取消订单
     * @param orderId
     * @return
     */
    @Transactional
    @Override
    public int cancelOrder(Long orderId) {
        // 更改已选课时状态
        List<SpokenUserCourseTime> spokenUserCourseTimes = userCourseTimeService.selectUserCourseTimeByOrderId(orderId);
        for (SpokenUserCourseTime spokenUserCourseTime : spokenUserCourseTimes) {
            spokenUserCourseTime.setStatus(UserCourseTimeStatus.CANCEL.getCode());
            userCourseTimeService.update(spokenUserCourseTime);
        }
        // 更改订单状态
        SpokenOrder spokenOrder = new SpokenOrder();
        spokenOrder.setStatus(OrderStatus.CANCEL.getCode());
        spokenOrder.setOrderId(orderId);
        int update = update(spokenOrder);
        if(update > 0){
            // 删除redis缓存
            String redisKey = "order-" + spokenOrder.getOrderNo();
            if(redisCache.hasKey(redisKey)){
                redisCache.deleteObject(redisKey);
            }
            return 1;
        }else{
            return update;
        }
    }

    @Override
    public Integer selectOrderCount(Integer status, String startDate, String endDate) {
        return orderMapper.selectOrderCount(status, startDate, endDate);
    }
}
